#include "filestorethread.h"

#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QStorageInfo>

#define WRITE_BUFFER_SIZE (60*1024*1024)

void myMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
    // 打开日志文件（追加模式）
    static QFile logFile("app_log.txt");
    if (!logFile.isOpen()) {
        logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
    }

    // 获取当前时间
    QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");

    // 根据日志类型格式化消息
    QString formattedMsg;
    switch (type) {
    case QtDebugMsg:
        formattedMsg = QString("[%1] DEBUG: %2").arg(timestamp).arg(msg);
        break;
    case QtInfoMsg:
        formattedMsg = QString("[%1] INFO: %2").arg(timestamp).arg(msg);
        break;
    case QtWarningMsg:
        formattedMsg = QString("[%1] WARNING: %2").arg(timestamp).arg(msg);
        break;
    case QtCriticalMsg:
        formattedMsg = QString("[%1] CRITICAL: %2").arg(timestamp).arg(msg);
        break;
    case QtFatalMsg:
        formattedMsg = QString("[%1] FATAL: %2").arg(timestamp).arg(msg);
        abort(); // 致命错误，终止程序
    }

    // 写入文件
    QTextStream out(&logFile);
    out << formattedMsg << "\n";

    // 如果需要同时输出到控制台，可以在这里添加：
    // fprintf(stderr, "%s\n", formattedMsg.toUtf8().constData());
}

FileStoreThread::FileStoreThread(QSemaphore* semaphore, QString fileDir, QObject *parent)
    : QThread{parent}
{
    m_storePath = fileDir;
    m_count = 0;
    m_semaphore = semaphore;
}

void FileStoreThread::run()
{
    qInstallMessageHandler(myMessageHandler);
    m_testData = generateData();
    quint64 recordIndex = 0;

    QStorageInfo storage(m_storePath);

    QString rootDir = storage.rootPath();

    while(1) {       
        m_semaphore->acquire();
        int availableCount = m_semaphore->available() + 1;
        recordIndex++ ;
        QDateTime currentSecond = QDateTime::currentDateTime();

        QString fileName = QString("%1.dat").arg(currentSecond.toString("yyyyMMdd_hhmmss_zzz"));
        QString fileDirAndName = m_storePath + "/" + fileName;
        if (writeData(fileDirAndName, m_testData) == false)
            continue;
        QDateTime lastReportTime = QDateTime::currentDateTime();
        qint64 mSecond = currentSecond.msecsTo(lastReportTime);

        qint64 freeDiskInMB = getFreeDisk(rootDir);

        QString indexStr = QString().sprintf("%8d: ", recordIndex);
        QString avalableStr = QString().sprintf("available semaphore: %8d: ", availableCount);
        QString freeDiskStr = QString().sprintf("path: %s, free: %8d MB, ", rootDir.toStdString().c_str(), freeDiskInMB);
        QString fileSizeStr = QString().sprintf("write size: %8d MB, used time: %8d ms, ", WRITE_BUFFER_SIZE/1000/1000, mSecond);
        QString speedStr = QString().sprintf("speed: %8.2f MB/s.", WRITE_BUFFER_SIZE * 1000.0 / mSecond/1000/1000);
        QString result = indexStr + avalableStr + freeDiskStr + fileSizeStr + speedStr;
        qDebug() << result;

        // 如果可用空间小于100MB，则退出程序
        if (freeDiskInMB < 100.0) {
            qCritical() << "disk is full, exit";
            return;
        }
    }
}

QByteArray FileStoreThread::generateData()
{
    const int chunkSize = WRITE_BUFFER_SIZE; // 60M的块大小
    QByteArray data(chunkSize, '\0');

    // 填充一些随机数据，而不是全零
    for (int i = 0; i < chunkSize; ++i) {
        data[i] = qrand() % 256;
    }

    return data;
}

bool FileStoreThread::writeData(QString fileName, QByteArray data)
{
    QFile file(fileName);

    if (!file.open(QIODevice::WriteOnly)) {
        qWarning() << "open file failed:" << fileName;
        return false;
    } else {
        int writeSize = file.write(data);
        file.close();
        if (writeSize > 0)
            return true;
        else
            return false;
    }
}

qint64 FileStoreThread::getFreeDisk(QString targetDrive)
{

    // 创建QStorageInfo对象，检查指定的磁盘
    QStorageInfo storage(targetDrive);

    // 检查磁盘是否有效、就绪且可写
    if (storage.isValid() && storage.isReady() && storage.isValid()) {
        // 获取可用空间（字节）
        qint64 availableBytes = storage.bytesAvailable();

        // 转换为MB（1 MB = 1024 * 1024 字节）
        double availableMB = availableBytes / (1024.0 * 1024.0);

        return availableMB;

    } else {
        // 如果磁盘无效或不可访问
        qCritical() << "disk error, exit";
        return -1;
    }

}
